# -*- coding: utf-8 -*-
"""
 * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-蓝鲸 PaaS 平台(BlueKing-PaaS) available.
 * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
"""
from typing import Optional

from requests.exceptions import (
    ChunkedEncodingError,
    ConnectionError,
    ConnectTimeout,
    ContentDecodingError,
    HTTPError,
    ProxyError,
    ReadTimeout,
    RequestException,
    Timeout,
)
from six.moves.urllib.parse import urlparse, urlunparse

from .utils import CurlRequest

__all__ = [
    "ChunkedEncodingError",
    "ConnectionError",
    "HTTPError",
    "ProxyError",
    "ReadTimeout",
    "ConnectTimeout",
    "ContentDecodingError",
    "Timeout",
    "BKAPIError",
    "UserNotAuthenticated",
    "ResponseError",
    "APIGatewayResponseError",
    "HTTPResponseError",
    "JSONResponseError",
]


class BKAPIError(Exception):
    pass


class UserNotAuthenticated(BKAPIError):
    """User not authenticated"""


class PathParamsMissing(BKAPIError):
    """Path params is missing"""


class ResponseError(RequestException, BKAPIError):
    """Response has error"""

    def __init__(self, *args, **kwargs):
        self._response_headers_representer = kwargs.pop("response_headers_representer", None)
        super(ResponseError, self).__init__(*args, **kwargs)

    @property
    def error_code(self):
        # type: (...) -> Optional[str]
        return self._response_headers_representer and self._response_headers_representer.error_code

    @property
    def error_message(self):
        # type: (...) -> Optional[str]
        return self._response_headers_representer and self._response_headers_representer.error_message

    @property
    def request_id(self):
        # type: (...) -> Optional[str]
        return self._response_headers_representer and self._response_headers_representer.request_id

    @property
    def curl_command(self):
        return CurlRequest(self.request).to_curl()

    @property
    def request_method(self):
        # type: (...) -> Optional[str]
        return self.request and self.request.method

    @property
    def request_url(self):
        # type: (...) -> str
        url = self.request and self.request.url
        if not url:
            return ""

        parsed_url = urlparse(url)
        return urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, "", "", ""))

    @property
    def response_status_code(self):
        # type: (...) -> Optional[int]
        # bool(response) is equal to response.ok
        return self.response.status_code if self.response is not None else None

    @property
    def response_text(self):
        # type: (...) -> Optional[str]
        return self.response.text if self.response is not None else None

    def response_json(self):
        return self.response.json() if self.response is not None else None

    def __str__(self):
        if self.response is None:
            return super(ResponseError, self).__str__()

        return "%s, status_code: %s, %s" % (
            super(ResponseError, self).__str__(),
            self.response.status_code,
            str(self._response_headers_representer or ""),
        )


class APIGatewayResponseError(ResponseError):
    """Request apigateway error, and the response is generated by the apigateway"""


class HTTPResponseError(ResponseError):
    """HTTP request status code error"""


class JSONResponseError(ResponseError):
    """The response content is not a valid json"""


class EndpointNotSetError(BKAPIError):
    """Endpoint is not set"""
